<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        class Socket {
            constructor({ url = '', token = '', roomId = '', callback = () => { } }) {
                this.url = url;
                this.callback = callback;
                this.token = token;
                this.roomId = roomId;
                this.ws = {};
                this.init();
            }

            init() {
                this.ws = new WebSocket(`wss://${this.url}`);
                // WebSocket连接成功时触发
                this.ws.onopen = () => this.onOpen(this.token, this.roomId);
                // WebSocket接受到信息时触发
                this.ws.onmessage = e => this.onMessage(e, this.callback);
                // WebSocket连接信息错误时触发
                this.ws.onerror = this.onError;
                // WebSocket关闭时触发
                this.ws.onclose = this.onClose;
            }

            onOpen(token, roomId) {
                // 连接时,根据身份校验事件,传参给服务端设置对应的连接信息
                this.send({
                    event: 'auth',
                    message: {
                        token,
                        roomId
                    }
                });
            }

            send(data) {
                this.ws.send(JSON.stringify(data));
            }

            onMessage(e, callback) {
                const data = JSON.parse(e.data);
                switch (data.event) {
                    case 'noAuth':
                        // 验证失败,返回登录页
                        location.href = '/login';
                        break;
                    case 'heartbeat':
                        // 心跳检测,当连接成功,服务端就会定时发起ping请求,需要回复,让服务端知道客户端在线,
                        this.send({
                            event: 'heartbeat',
                            message: 'pong'
                        });
                        clearTimeout(this.pingTimeout);
                        this.pingTimeout = setTimeout(() => {
                            this.close();
                            this.onError();
                        }, 30000 + 1000);
                        break;
                    default:
                        callback(data);
                }
            }

            onError() {
                console.log('websocket连接错误');
                // 连接出错了,1S后重新连接
                setTimeout(() => {
                    this.init();
                }, 1000);
            }

            onClose() {
                console.log('websocket连接断开');
            }

            close() {
                // 关闭websocket连接需要关闭心跳检测定时器,防止断开后原来的定时器还在运行连接
                clearTimeout(this.pingTimeout);
                this.ws.close();
            }
        }

    </script>
</body>

</html>